#include "PrecompiledHeader_Voxel.h"
#include "World.h"

/*--------------------------------------------------------------------------*/

World::World(const NodeCreation& nc)	
{
	m_nodeCreation = nc;
	m_nodeCreation.m_flags |= ENodeFlag::CubicShape;

	m_noise1.SetFrequency(2.0f);		//czestotlisoc?
	m_noise1.SetPersistence(2.0f);		//zmiennosc?
	m_noise1.SetLacunarity(2.0f);
	m_noise1.SetOctaveCount(3.0f);

	m_noise2.SetFrequency(4.0f);		//czestotlisoc?
	m_noise2.SetPersistence(3.0f);		//zmiennosc?
	m_noise2.SetLacunarity(2.0f);
	m_noise2.SetOctaveCount(2.0f);
}

/*--------------------------------------------------------------------------*/

World::~World()
{

}

/*--------------------------------------------------------------------------*/

void World::Init()
{
	Chunk::InitCommons();
	this->m_chunks = new Chunk*[TCHUNK_X * TCHUNK_Y * TCHUNK_Z];

	ChunkCreation cc;
	cc.m_owner = this;

	for (int x = 0; x < TCHUNK_X; ++x)
	{
		for (int y = 0; y < TCHUNK_Y; ++y)
		{
			for (int z = 0; z < TCHUNK_Z; ++z)
			{
				int id = TID(x, y, z);

				cc.m_x = x * CHUNK_X;
				cc.m_y = y * CHUNK_Y;
				cc.m_z = z * CHUNK_Z;

				this->m_chunks[id] = new Chunk(m_nodeCreation, cc);
				this->m_chunks[id]->SetPosition(glm::vec3(x * CHUNK_X, y * CHUNK_Y, z * CHUNK_Z));
			}
		}
	}

	for (int x = 0; x < TCHUNK_X; ++x)
	{
		for (int y = 0; y < TCHUNK_Y; ++y)
		{
			for (int z = 0; z < TCHUNK_Z; ++z)
			{
				Chunk* nx = NULL;
				Chunk* ny = NULL;
				Chunk* nz = NULL;
				Chunk* px = NULL;
				Chunk* py = NULL;
				Chunk* pz = NULL;

				int i = 0;

				if (x-1 >= 0)	
				{
					i = TID(x-1, y, z);
					nx = this->m_chunks[i];
				}

				if (x+1 < TCHUNK_X)
				{
					i = TID(x+1, y, z);
					px = this->m_chunks[i];
				}

				if (y-1 >= 0)
				{
					i = TID(x, y-1, z);
					ny = this->m_chunks[i];
				}

				if (y+1 < TCHUNK_Y)
				{
					i = TID(x, y+1, z);
					py = this->m_chunks[i];
				}

				if (z-1 >= 0)
				{
					i = TID(x, y, z-1);
					nz = this->m_chunks[i];
				}

				if (z+1 < TCHUNK_Z)
				{
					i = TID(x, y, z+1);
					pz = this->m_chunks[i];
				}

				int id = TID(x, y, z);
				this->m_chunks[id]->SetNeighbourhood(nx, px, ny, py, nz, pz);
				
				AssertLogI(true, "%02d %p %d %d %d => %p %p %p %p %p %p", id, this->m_chunks[id], x, y, z, nx, px, ny, py, nz, pz);
			}
		}
	}

	for (int x = 0; x < TCHUNK_X; ++x)
	{
		for (int y = 0; y < TCHUNK_Y; ++y)
		{
			for (int z = 0; z < TCHUNK_Z; ++z)
			{
				Chunk* nx = NULL;
				Chunk* ny = NULL;
				Chunk* nz = NULL;
				Chunk* px = NULL;
				Chunk* py = NULL;
				Chunk* pz = NULL;
				Chunk* me = NULL;

				me = this->m_chunks[TID(x, y, z)];

				if (x-1 >= 0)
					nx = this->m_chunks[TID(x-1, y, z)];

				if (x+1 < TCHUNK_X)
					px = this->m_chunks[TID(x+1, y, z)];

				if (y-1 >= 0)
					ny = this->m_chunks[TID(x, y-1, z)];

				if (y+1 < TCHUNK_Y)
					py = this->m_chunks[TID(x, y+1, z)];

				if (z-1 >= 0)
					nz = this->m_chunks[TID(x, y, z-1)];

				if (z+1 < TCHUNK_Z)
					pz = this->m_chunks[TID(x, y, z+1)];

				
				/*--------------------------------------------------------------------------*/
				AssertLogC(me->GetNX() != nx, "NX1");
				if (nx)
					AssertLogC(nx->GetPX() != me, "NX2");
				/*--------------------------------------------------------------------------*/
				AssertLogC(me->GetPX() != px, "PX1");
				if (px)
					AssertLogC(px->GetNX() != me, "PX2");
				/*--------------------------------------------------------------------------*/
				/*--------------------------------------------------------------------------*/
				AssertLogC(me->GetNY() != ny, "NY1");
				if (ny)
					AssertLogC(ny->GetPY() != me, "NY2");
				/*--------------------------------------------------------------------------*/
				AssertLogC(me->GetPY() != py, "PY1");
				if (py)
					AssertLogC(py->GetNY() != me, "PY2");
				/*--------------------------------------------------------------------------*/
				/*--------------------------------------------------------------------------*/
				AssertLogC(me->GetNZ() != nz, "NZ1");
				if (nz)
					AssertLogC(nz->GetPZ() != me, "NZ2");
				/*--------------------------------------------------------------------------*/
				AssertLogC(me->GetPZ() != pz, "PZ1");
				if (pz)
					AssertLogC(pz->GetNZ() != me, "PZ2");
				/*--------------------------------------------------------------------------*/
			}
		}
	}

	for (int x = 0; x < TCHUNK_X; ++x)
	{
		for (int y = 0; y < TCHUNK_Y; ++y)
		{
			for (int z = 0; z < TCHUNK_Z; ++z)
			{
				int id = TID(x, y, z);
				this->m_chunks[id]->UpdateVBO();
			}
		}
	}
}

/*--------------------------------------------------------------------------*/

void World::DrawDebugHud()
{
	g_Renderer->DrawText2D(NULL, "WORLD DEBUG INFO:", glm::vec2(10, 100), Color::White);
}

/*--------------------------------------------------------------------------*/

void World::Tick()
{
	if (g_Keyboard->GetKeyState(EKey::k_space))
	{
		m_chunks[0]->Boom(g_Scene->GetFreeCamera()->GetPosition());
	}

	for (int x = 0; x < TCHUNK_X; ++x)
	{
		for (int y = 0; y < TCHUNK_Y; ++y)
		{
			for (int z = 0; z < TCHUNK_Z; ++z)
			{
				int id = TID(x, y, z);
				this->m_chunks[id]->UpdateVBO();
			}
		}
	}
}

/*--------------------------------------------------------------------------*/

int World::GetHeight( int x, int y )
{
	double nrm = m_noise1.GetValue(double(x) * 0.0005, double(y) * 0.0005, double(CHUNK_Z / 2) * 0.0005);
	double noise1_result = nrm * double(CHUNK_Z) * 0.5;
	return glm::abs(noise1_result + (double(TCHUNK_Z * CHUNK_Z / 2)));
}

/*--------------------------------------------------------------------------*/

bool World::IsCave( int x, int y, int z )
{
	return false;

	double nrm = m_noise2.GetValue(double(x) * 0.0005, double(y) * 0.0005, double(z) * 0.0005);
	return nrm > -0.1 && nrm < 0.1;
}

/*--------------------------------------------------------------------------*/
